#include <errno.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <pthread.h>
#include <arpa/inet.h>
#define MAXLNE  4096

struct socket_client_info
{
    int connfd;
    struct sockaddr_in client;
};

typedef struct socket_client_info socket_client_info_t;

//一个线程8M,4G内存，最多512个线程（仅仅是线程就占用了4个G）
//C10k
void *client_routine(void *arg) { //
	// int connfd = *(int *)arg;
    socket_client_info_t cli_info = *(socket_client_info_t *)arg;
	char buff[MAXLNE];
	while (1) {
        int n = recv(cli_info.connfd, buff, MAXLNE, 0);
        if (n > 0) {
            buff[n] = '\0';
            printf("recv msg from client: %s\n", buff);
            printf("connfd is %d\n", cli_info.connfd);
            printf("client ip: %s, port: %d\n", inet_ntoa(cli_info.client.sin_addr), ntohs(cli_info.client.sin_port));
            send(cli_info.connfd, buff, n, 0);
        } else if (n == 0) {
            printf("close connfd is %d\n", cli_info.connfd);
            printf("client ip: %s, port: %d\n", inet_ntoa(cli_info.client.sin_addr), ntohs(cli_info.client.sin_port));
            close(cli_info.connfd);
  	        break;
        }
	}
	return NULL;
}
int main(int argc, char **argv) 
{
    int listenfd, connfd, n;
    socket_client_info_t cli_info;
    struct sockaddr_in servaddr;
    char buff[MAXLNE];
    if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
        printf("create socket error: %s(errno: %d)\n", strerror(errno), errno);
        return 0;
    }
    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(9999);
    if (bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) == -1) {
        printf("bind socket error: %s(errno: %d)\n", strerror(errno), errno);
        return 0;
    }
    //listen接口之后会一直监听客户端的连接，每次客户端连接，都会和其创建连接（三次连接时内核完成的，不是由应用程序去控制的）
    //三次握手不发生在任何API中，协议栈本身被动完成的。
    if (listen(listenfd, 10) == -1) {
        printf("listen socket error: %s(errno: %d)\n", strerror(errno), errno);
        return 0;
    }
       
    while (1) {
        struct sockaddr_in client;
        socklen_t len = sizeof(client);
        if ((connfd = accept(listenfd, (struct sockaddr *)&client, &len)) == -1) {
            printf("accept socket error: %s(errno: %d)\n", strerror(errno), errno);
            return 0;
        }
        cli_info.connfd = connfd;
        cli_info.client = client;
        // printf("accept a new client: %s:%d\n", inet_ntoa(client.sin_addr), ntohs(client.sin_port));
        //1个客户端1个线程去处理，早期的网络模型就是这种模式
        //缺点：不适用于当前高并发的情况。
        //优点：逻辑简单
        pthread_t threadid;
        pthread_create(&threadid, NULL, client_routine, (void*)&cli_info);
    }
   
    close(listenfd);
    return 0;
}